package mge.ui
{
  import __AS3__.vec.Vector;
  import flash.display.DisplayObjectContainer;
  
  import flash.display.Bitmap;
  import flash.display.Sprite;
  import flash.events.Event;
  import flash.events.MouseEvent;
  import flash.geom.Matrix;
  
  import mge.Ease;
  import mge.Timer;
  
  public class Button
  {
    public function Button(name:String, bmpEnabled:Bitmap, bmpDisabled:Bitmap, bmpSelected:Bitmap, bmpPressed:Bitmap, parent:DisplayObjectContainer)
    {
      sprite = new Sprite;
      
      this.bmpEnabled = bmpEnabled;
      this.bmpDisabled = bmpDisabled;
      this.bmpSelected = bmpSelected;
      this.bmpPressed = bmpPressed;
      this.parent = parent;
      this._name = name;
      
      parent.addChild(sprite);
      sprite.addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
      sprite.addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
      sprite.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
      sprite.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
      
      render(bmpEnabled);
      
      saveMatrix();
      
      sprite.buttonMode = _enabled;
      sprite.tabEnabled = false;
    }
    
    public function clear():void
    {
      parent.removeChild(sprite);
      sprite.removeEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
      sprite.removeEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
      sprite.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
      sprite.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
      parent.removeEventListener(Event.ENTER_FRAME, onEnterFrame);
    }
    
    public function set enabled(val:Boolean):void
    {
      if (_enabled == val) return;
      _enabled = val;
      sprite.buttonMode = _enabled;
      
      render(_enabled ? bmpEnabled : bmpDisabled);
    }
    
    public function get enabled():Boolean
    {
        return _enabled;
    }
    
    private function render(bmp:Bitmap):void
    {
      sprite.graphics.clear();
      sprite.graphics.beginBitmapFill(bmp.bitmapData, null, true, true);
      sprite.graphics.drawRect(0, 0, bmp.width, bmp.height);
      sprite.graphics.endFill();
    }
    
    public function onMouseOver(e:MouseEvent):void
    {
      if (!_enabled) return;
      scale = 1.1;
      render(bmpSelected);
      over = true;
    }
    
    public function onMouseOut(e:MouseEvent):void
    {
      over = false;
      scale = 1;
      if (!_enabled)
      {
          render(bmpDisabled);
          return;
      }
      if (_selected)
        render(bmpSelected);
      else
        render(bmpEnabled);
    }
    
    public function onMouseDown(e:MouseEvent):void
    {
      if (!_enabled) return;
      over = true;
      render(bmpPressed);
    }
    
    public function onMouseUp(e:MouseEvent):void
    {
      if (!_enabled) return;
      if (over)
      {
        render(bmpSelected);
        click();
      }
      else
        render(bmpEnabled);
    }
    
    public function set scale(val:Number):void
    {
      _scale = val;
      
      var hw:int = bmpEnabled.width / 2;
      var hh:int = bmpEnabled.height / 2;
      
      var m:Matrix = originalMatrix.clone();
      
      sprite.transform.matrix = originalMatrix;
      
      m.translate(-sprite.x-hw, -sprite.y-hh);
      m.scale(_scale, _scale);
      m.translate(sprite.x+hw, sprite.y+hh);
      
      sprite.transform.matrix = m;
    }
    
    private function saveMatrix():void
    {
      originalMatrix = sprite.transform.matrix.clone();
    }
    
    private function click():void
    {
      timer = new mge.Timer(250);
      timer.start();
      parent.addEventListener(Event.ENTER_FRAME, onEnterFrame);
      
      for (var i:int = 0; i < onClickCallbacks.length; i++)
        onClickCallbacks[i](name);
    }
    
    private function onEnterFrame(e:Event):void
    {
      scale = 1 + 0.2 * timer.getDelta(new Ease(Ease.sinPi_00));
      if (timer.finished())
      {
        scale = 1;
        parent.removeEventListener(Event.ENTER_FRAME, onEnterFrame);
        if (!enabled)
        {
            render(bmpDisabled)
            return;
        }
        else
            render(over || _selected ? bmpSelected : bmpEnabled);
      }
    }
    
    public function addOnClickCallback(f:Function):void
    {
      onClickCallbacks.push(f);
    }
    
    public function removeOnClickCallback(f:Function):void
    {
      for (var i:int = 0; i < onClickCallbacks.length; i++)
        if (f == onClickCallbacks[i])
          onClickCallbacks.splice(i--, 1);
    }
    
    public function set x(val:Number):void { sprite.x = val; saveMatrix() }
    public function get x():Number { return sprite.x; }
    
    public function set y(val:Number):void { sprite.y = val; saveMatrix() }
    public function get y():Number { return sprite.y; }
    
    public function get width():int { return bmpEnabled.width; }
    public function get height():int { return bmpEnabled.height; }
    
    private var _enabled:Boolean = true;
    private var over:Boolean;
    
    private var sprite:Sprite;
    
    private var bmpEnabled:Bitmap;
    private var bmpDisabled:Bitmap;
    private var bmpSelected:Bitmap;
    private var bmpPressed:Bitmap;
    
    private var _scale:Number = 1;
    private var originalMatrix:Matrix;
    
    public var parent:DisplayObjectContainer;
    
    private var timer:mge.Timer;
    
    public function get name():String { return _name; }
    private var _name:String;
    private var onClickCallbacks:Vector.<Function> = new Vector.<Function>;
    
    public function set selected(val:Boolean):void
    {
        _selected = val;
        if (_selected)
            render(bmpSelected);
        else
            onMouseOut(null);
    }
    private var _selected:Boolean;
    
    public var keyboardNavigable:Boolean = true;

  }
}